package cn.com.qtgl.apis.iam.comp.service;

import cn.com.qtgl.apis.builtin.model.vo.Department;
import cn.com.qtgl.apis.builtin.model.vo.Post;
import cn.com.qtgl.apis.iam.comp.IamConfig;
import cn.com.qtgl.apis.iam.model.vo.*;
import cn.melonlib.apis.support.comp.service.ApiRequestRecordService;
import cn.melonlib.apis.support.model.enums.ApiOperationType;
import cn.melonlib.apis.support.model.enums.ApiRange;
import cn.melonlib.cores.commons.comp.web.ctrl.BasicController;
import cn.melonlib.cores.graphql.comp.utils.GraphQLTools;
import cn.melonlib.cores.identification.comp.messenger.IdentificationMessenger;
import cn.melonlib.objects.maps.JsonMap;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import okhttp3.MediaType;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class IamCacheService extends ApplicationObjectSupport {

//    @Resource
//    private OkHttpClient httpClient;

    @Resource
    private IamConfig iamConfig;

    @Resource
    private GraphQLTools graphQLTools;

    @Resource
    private ObjectMapper jsonMapper;

    @Resource
    private ApiRequestRecordService apiRequestRecordService;

    @Resource
    @Lazy
    private IdentificationMessenger identificationMessenger;
    /**
     * 通过iamApi接口获取岗位信息，岗位信息经过缓存处理。
     * @return
     * @throws Exception
     */
//    @Cacheable(value = {"iamApi"},key = "'posts'")
    public IamApiResult<PostEdges> posts() throws Exception{
        MediaType mediaType=MediaType.parse(BasicController.APPLICATION_JSON_UTF8_VALUE);
        StringBuilder query=new StringBuilder("query posts { posts")
                .append(graphQLTools.createQuery(new GraphQLTools.QueryTypeReference<IamApiResult<PostEdges>>(){})).append("}");
        JsonMap<Object> params=JsonMap.createMap().append("operationName","posts")
                .append("query",query.toString())
                .append("variables",JsonMap.createMap());
        Map<String, Map<String,IamApiResult<PostEdges>>> packages=jsonMapper.readValue(apiRequestRecordService.sendRequest(iamConfig.getIam(),query.toString(),params, ApiOperationType.QUERY.name(),
                        ApiRange.IAM.name(), identificationMessenger.getOrganization().getCode(),"posts",JsonMap.createMap()).getResponse()
                , new TypeReference<Map<String,Map<String,IamApiResult<PostEdges>>>>() {
        });
        return packages.get("data").get("posts");
    }

    public Post getPost(String code) throws Exception{
        MediaType mediaType=MediaType.parse(BasicController.APPLICATION_JSON_UTF8_VALUE);
        StringBuilder query=new StringBuilder("query posts($filter:Filter) { posts(filter:$filter)")
                .append(graphQLTools.createQuery(new GraphQLTools.QueryTypeReference<IamApiResult<PostEdges>>(){})).append("}");
        JsonMap<Object> params=JsonMap.createMap().append("operationName","posts")
                .append("query",query.toString())
                .append("variables",JsonMap.createMap().append("filter",JsonMap.createMap().append("code",JsonMap.createMap().append("eq",code))));
        Map<String, Map<String,IamApiResult<PostEdges>>> packages=jsonMapper.readValue(apiRequestRecordService.sendRequest(iamConfig.getIam(),query.toString(),params, ApiOperationType.QUERY.name(),
                ApiRange.IAM.name(), identificationMessenger.getOrganization().getCode(),"posts",JsonMap.createMap()).getResponse(), new TypeReference<Map<String,Map<String,IamApiResult<PostEdges>>>>() {
        });
        return packages.get("data").get("posts").getEdges().get(0).getNode();
    }

    /**
     * 获取岗位key value映射
     * @return
     * @throws Exception
     */
//    @Cacheable(value = {"iamMaps"},key = "'postMap'")
    public JsonMap<Post> postMap() throws Exception{
        return posts().getEdges().stream().map(PostEdges::getNode).reduce(JsonMap.<Post>createMap(),(postMap, post)->postMap.append(post.getCode(),post),(m, p)->null);
    }


    /**
     * 通过访问iam接口获取用户信息
     * @return
     * @throws Exception
     */
//    @Cacheable(value = {"iamApi"},key = "'users'")
    public IamApiResult<UserEdges> users() throws Exception{
        MediaType mediaType=MediaType.parse(BasicController.APPLICATION_JSON_UTF8_VALUE);
        StringBuilder query=new StringBuilder("query users { users")
                .append(graphQLTools.createQuery(new GraphQLTools.QueryTypeReference<IamApiResult<UserEdges>>(){})).append("}");
        JsonMap<Object> params=JsonMap.createMap().append("operationName","users")
                .append("query",query.toString())
                .append("variables",JsonMap.createMap());
        Map<String, Map<String,IamApiResult<UserEdges>>> packages=jsonMapper.readValue(apiRequestRecordService.sendRequest(iamConfig.getIam(),query.toString(),params, ApiOperationType.QUERY.name(),
                ApiRange.IAM.name(), identificationMessenger.getOrganization().getCode(),"users",JsonMap.createMap()).getResponse(), new TypeReference<Map<String,Map<String,IamApiResult<UserEdges>>>>() {
        });
        packages.get("data").get("users").getEdges().stream().forEach(node->{
            node.getNode().setLoginName(node.getNode().getOpenid());
        });
        return packages.get("data").get("users");
    }



//    @Cacheable(value = {"iamApi"},key = "'departments'")
    public IamApiResult<DepartmentEdges> departments() throws Exception{
        MediaType mediaType=MediaType.parse(BasicController.APPLICATION_JSON_UTF8_VALUE);
        StringBuilder query=new StringBuilder("query departments { departments")
                .append(graphQLTools.createQuery(new GraphQLTools.QueryTypeReference<IamApiResult<DepartmentEdges>>(){})).append("}");
        JsonMap<Object> params=JsonMap.createMap().append("operationName","departments")
                .append("query",query.toString())
                .append("variables",JsonMap.createMap());
        Map<String, Map<String,IamApiResult<DepartmentEdges>>> packages=jsonMapper.readValue(apiRequestRecordService.sendRequest(iamConfig.getIam(),query.toString(),params, ApiOperationType.QUERY.name(),
                ApiRange.IAM.name(), identificationMessenger.getOrganization().getCode(),"departments",JsonMap.createMap()).getResponse(), new TypeReference<Map<String,Map<String,IamApiResult<DepartmentEdges>>>>() {
        });
        return packages.get("data").get("departments");
    }
    public Department department(String code) throws Exception{
        MediaType mediaType=MediaType.parse(BasicController.APPLICATION_JSON_UTF8_VALUE);
        StringBuilder query=new StringBuilder("query departments ($filter:Filter){ departments(filter:$filter)")
                .append(graphQLTools.createQuery(new GraphQLTools.QueryTypeReference<IamApiResult<DepartmentEdges>>(){})).append("}");
        JsonMap<Object> params=JsonMap.createMap().append("operationName","departments")
                .append("query",query.toString())
                .append("variables",JsonMap.createMap().append("code",JsonMap.createMap().append("eq",code)));
        Map<String, Map<String,IamApiResult<DepartmentEdges>>> packages=jsonMapper.readValue(apiRequestRecordService.sendRequest(iamConfig.getIam(),query.toString(),params, ApiOperationType.QUERY.name(),
                ApiRange.IAM.name(), identificationMessenger.getOrganization().getCode(),"departments",JsonMap.createMap()).getResponse(), new TypeReference<Map<String,Map<String,IamApiResult<DepartmentEdges>>>>() {
        });
        return packages.get("data").get("departments").getEdges().get(0).getNode();
    }

//    @Cacheable(value = {"iamMaps"},key = "'departmentMap'")
    public JsonMap<Department> departmentMap() throws Exception{
        return this.departments().getEdges().stream().map(DepartmentEdges::getNode)
                .reduce(JsonMap.createMap(),(userMap, department)->userMap.append(department.getCode(),department),(um, u)->null);
    }

//    @Cacheable(value = {"iamMaps"},key = "'user_'+#account")
    public User getUser(String account) throws Exception{
        MediaType mediaType=MediaType.parse(BasicController.APPLICATION_JSON_UTF8_VALUE);
        StringBuilder query=new StringBuilder("query users ($filter:Filter){ users(filter:$filter)")
                .append(graphQLTools.createQuery(new GraphQLTools.QueryTypeReference<IamApiResult<UserEdges>>(){})).append("}");
        JsonMap<Object> params=JsonMap.createMap().append("operationName","users")
                .append("query",query.toString())
                .append("variables",JsonMap.createMap().append("filter",JsonMap.createMap()
                        .append("account",JsonMap.createMap().append("eq",account))
                ));
            Map<String, Map<String,IamApiResult<UserEdges>>> packages=jsonMapper.readValue(apiRequestRecordService.sendRequest(iamConfig.getIam(),query.toString(),params, ApiOperationType.QUERY.name(),
                    ApiRange.IAM.name(), identificationMessenger.getOrganization().getCode(),"users",JsonMap.createMap()).getResponse(), new TypeReference<Map<String,Map<String,IamApiResult<UserEdges>>>>() {
            });
            User user=packages.get("data").get("users").getEdges().get(0).getNode();
            user.setLoginName(user.getOpenid());
            return user;
    }


    public JsonMap<User> validateUser(List<String> userFiltersList,String account) throws Exception{
        StringBuilder queries=new StringBuilder("query users (")
                .append(String.join(",", userFiltersList.stream().reduce(new ArrayList<String>(userFiltersList.size()), (list, filters) -> {
                    list.add("$filter" + list.size() + ":Filter");
                    return list;
                }, (list, f) -> null)))
                .append(")").append("{")
                .append(String.join("\r\n", userFiltersList.stream().reduce(new ArrayList<String>(userFiltersList.size()), (list, filters) -> {
                    StringBuilder query = new StringBuilder("users").append(list.size()).append(":users(filter").append(":$filter").append(list.size()).append(")")
                            .append(graphQLTools.createQuery(new GraphQLTools.QueryTypeReference<IamApiResult<UserEdges>>() {
                            }));
                    list.add(query.toString());
                    return list;
                }, (list, f) -> null)))
                .append("}");
                JsonMap<Object> params=JsonMap.createMap().append("operationName","users")
                        .append("query",queries.toString())
                        .append("variables",userFiltersList.stream().reduce(JsonMap.createMap(),(prms,filters)->
                                prms.append("filter"+prms.size(),JsonMap.createMap().append("account",
                                        JsonMap.createMap().append("eq",account))
                                .append("positions", JsonMap.createMap().append("in",Arrays.stream(filters.split(",")).collect(Collectors.toList())))
                        ),(p, f)->null));
                Map<String, Map<String,IamApiResult<UserEdges>>> packages=jsonMapper.readValue(apiRequestRecordService.sendRequest(iamConfig.getIam(),queries.toString(),params, ApiOperationType.QUERY.name(),
                        ApiRange.IAM.name(), identificationMessenger.getOrganization().getCode(),"users",JsonMap.createMap()).getResponse(), new TypeReference<Map<String,Map<String,IamApiResult<UserEdges>>>>() {
                });
                return userFiltersList.stream().reduce(ResultInfo.createResult(JsonMap.<User>createMap(),0),(result,f)->{
                        result.getData().append(f,packages.get("data").get("users"+result.getIndex()).getEdges().stream().reduce(null,(e,n)->n.getNode(),(e,n)->null));
                        result.next();
                        return result;
                    },(r, f)->null).getData();
    }

    public List<User> filterUser(List<String> userFiltersList,String url,String tenant) throws Exception{
        StringBuilder queries=new StringBuilder("query users (")
                .append(String.join(",", userFiltersList.stream().reduce(new ArrayList<String>(userFiltersList.size()), (list, filters) -> {
                    list.add("$filter" + list.size() + ":Filter");
                    return list;
                }, (list, f) -> null)))
                .append(")").append("{")
                .append(String.join("\r\n", userFiltersList.stream().reduce(new ArrayList<String>(userFiltersList.size()), (list, filters) -> {
                    StringBuilder query = new StringBuilder("users").append(list.size()).append(":users(position:\"*:*\",filter").append(":$filter").append(list.size()).append(")")
                            .append(graphQLTools.createQuery(new GraphQLTools.QueryTypeReference<IamApiResult<UserEdges>>() {
                            }));
                    list.add(query.toString());
                    return list;
                }, (list, f) -> null)))
                .append("}");
                JsonMap<Object> params=JsonMap.createMap().append("operationName","users")
                        .append("query",queries.toString())
                        .append("variables",userFiltersList.stream().reduce(JsonMap.createMap(),(prms,filters)->
                                prms.append("filter"+prms.size(),JsonMap.createMap()
                                .append("positions", JsonMap.createMap().append("in",Arrays.stream(filters.split(",")).collect(Collectors.toList())))
                        ),(p, f)->null));
                Map<String, Map<String,IamApiResult<UserEdges>>> packages=jsonMapper.readValue(apiRequestRecordService.sendRequest(url,queries.toString(),params, ApiOperationType.QUERY.name(),
                        ApiRange.IAM.name(), tenant,"users",JsonMap.createMap()).getResponse(), new TypeReference<Map<String,Map<String,IamApiResult<UserEdges>>>>() {
                });

                return userFiltersList.stream().reduce(ResultInfo.createResult(new ArrayList<User>(),0),(result,f)->{
                            result.getData().addAll(packages.get("data").get("users"+result.getIndex()).getEdges().stream().map(edge->{
                                User user=edge.getNode();
                                user.setLoginName(user.getOpenid());
                                return user;
                            }).collect(Collectors.toList()));
                            result.next();
                            return result;
                        }
                        ,(r, f)->null).getData();
    }
    public List<User> filterUser(List<String> userFiltersList) throws Exception{
        return this.filterUser(userFiltersList,iamConfig.getIam(),identificationMessenger.getOrganization().getCode());
    }

    @Data
    private static class ResultInfo<DATA>{
        private DATA data;
        private Integer index;

        public void next(){
            index=index+1;
        }

        private  ResultInfo(DATA data, Integer index) {
            this.data = data;
            this.index = index;
        }

        public static <DATA>ResultInfo<DATA> createResult(DATA data,Integer index){
            return new ResultInfo<>(data,index);
        }
    }
}
